<template>
    <div ref="terminal" id="Terminal" class="xterm"></div>
    <!-- <button @click="tt">close</button> -->
  </template>
  <script lang="ts" setup>
  import WebSocketBean from '@/util/websocket/WebSocketBean'
  import { IWebSocketBeanParam } from '@/util/websocket/websocket'
  import { nextTick, onMounted, ref, reactive, onUnmounted, onBeforeMount } from 'vue'
  import 'xterm/css/xterm.css'
  import 'xterm/lib/xterm.js'
  import { IBufferRange, IDecoration, IDecorationOptions, IDisposable, ILinkProvider, IMarker, ITerminalAddon, Terminal } from 'xterm'
  import { Message } from '@/entity/entitys'
  // xterm.js的插件，使终端的尺寸适合包含元素。
  import { FitAddon } from 'xterm-addon-fit'
  // xterm.js的附加组件，用于附加到Web Socket
  import { AttachAddon } from 'xterm-addon-attach'
  let wsTime: any = reactive<any>("");
  //import System from '~/utils/System'
  let term: Terminal = reactive<Terminal>(new Terminal({
    rows: 40, //行数，影响最小高度
    cols: 100, // 列数，影响最小宽度
    convertEol: true, //启用时，光标将设置为下一行的开头
    scrollback: 50, //终端中的滚动条回滚量
    disableStdin: false, //是否应禁用输入。
    cursorStyle: "underline", //光标样式
    cursorBlink: true, //光标闪烁
    theme: {
      foreground: "#F8F8F8",
      background: "#2D2E2C",
      cursor: "help", //设置光标
  
    },
    fontFamily: '"Cascadia Code", Menlo, monospace',
  }));
  let fitAddon: FitAddon = new FitAddon();
  const terminal = ref();
  
  // 用户输入
  let command: String = reactive<String>("");
  onMounted(() => {
    if ("WebSocket" in window) {
      nextTick(() => {
        userWrite();
      });
      start();
    } else {
      console.log("浏览器不支持 WebSocket..");
    }
  
  })
  
  onUnmounted(() => {
    close();
  })
  enum MessageType {
    /**
     * 收到发来的消息
     */
    Get,
    /**
     * 发送到服务器的消息
     */
    Send,
    /**
     * 通知
     */
    Message
  }
  
  const conf = reactive({
    status: '未连接',
    messagetype: {
      [MessageType.Get]: '收到',
      [MessageType.Send]: '发送',
      [MessageType.Message]: '通知'
    } as any,
    message: [] as {
      time: any
      type: MessageType
      data: any
    }[],
    url: 'ws://127.0.0.1:5555',
    send: ''
  })
  
  const addMessage = (type: MessageType, ctx: any) => {
    conf.message.push({
      time: new Date().toJSON(),
      type: type,
      data: ctx
    })
  }
  
  const sendSuffix = ''
  
  /**
  * 获取连接参数，也可以直接写入，这里是因为对地址进行了配置，所以每次连接都更新一次地址
  */
  const getParam = () => {
    return {
      url: conf.url,
      needReconnect: true,
      reconnectGapTime: 3000,
      sendSuffix,
      messageSuffix: sendSuffix,
      heartSend: 'JAVA',
      heartGet: 'JAVA',
      heartGapTime: 10000,
      onopen: () => {
        addMessage(MessageType.Message, '连接成功')
      },
      onmessage: (data: any) => {
        //console.log("data.data: " + data.data.message_type)
        let message: Message =JSON.parse(data.data) as Message;
        if (message.message_type != "HEARTBEAT") {
          //sp.forEach((ctx: any) => {
            term.write('\r\n')
            writeOfColor(message.data, "0;", "37m");
            term.write('\r\n$ ')
            addMessage(MessageType.Get, message.data)
          //})
        }else{
          console.log("HEARTBEAT 心跳测试: " + message.data)
        }
  
  
      },
      onerror: () => {
        addMessage(MessageType.Message, '连接失败:' + conf.url)
      }
    } as IWebSocketBeanParam
  }
  interface Info {
    Message_type: string;
    data:string;
  }
  /**
  * websocket示例，主要维护和使用对象
  */
  const ws = new WebSocketBean(getParam())
  const start = () => {
    // ws.start()
    ws.start(getParam())
    console.log("已建立连接：", event);
    // 输入换行符可让终端显示当前用户的工作路径
    // ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
    // 窗口自适应插件
    // 窗口尺寸变化时，终端尺寸自适应
  
    fitAddon.activate(term)
    //给新的这个ws服务使用依赖设置样式
    term.loadAddon(fitAddon);
    //给新的这个ws服务使用依赖初始化
    //term.loadAddon(attachAddon)
    term.open(terminal.value);
    // // 聚焦闪烁光标
    term.focus();
    ////先默认一次适应大小
    setTimeout(() => {
      fitAddon.fit();
    }, 1000)
    window.onresize = () => {
      fitAddon.fit();
    };
    writeDefaultInfo();
  }
  
  // 自定义终端默认展示内容
  function writeDefaultInfo() {
    let defaultInfo = [
      "┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ",
      "│                                                                            │ ",
      "│  \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m                                                  │ ",
      "│                                                                            │ ",
      "└────────────────────────────────────────────────────────────────────────────┘ ",
    ];
    // 测试颜色区间
    // let arr = Array.from({length:100},(v,i)=>v = i)
    // console.log(arr)
    // arr.map((item,i) => {
    //     defaultInfo.push(`Hello from \x1B[1;3;${i}m ${i} \x1B[0m  \u2764\ufe0f   ${i}`)
    // })
    term.write(defaultInfo.join("\n\r"));
    //writeOfColor("\n\r我是加粗斜体红色的字呀", "1;3;", "31m");
    term.write('\n\r$ ')
  };
  //
  function writeOfColor(txt: string | ArrayBuffer | null, fontCss = "", bgColor = "") {
    // 在Linux脚本中以 \x1B[ 开始，中间前部分是样式+内容，以 \x1B[0m 结尾
    // 示例 \x1B[1;3;31m 内容 \x1B[0m
    // fontCss
    // 0;-4;字体样式（0;正常 1;加粗 2;变细 3;斜体 4;下划线）
    // bgColor
    // 30m-37m字体颜色（30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色）
    // 40m-47m背景颜色（40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色）
    term.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`);
  };
  
  // 监听输入
  function userWrite() {
    term.onData((e) => {
      switch (e) {
        case "\u0003": // Ctrl+C
          term.write("^C ");
          term.write("\r\n$ ");
          break;
        case "\r": // Enter
          if (command == "clear") {
            term.clear()
            fitAddon.fit();
            command = "";
            term.write('\r\n$ ')
          } else if(command!=""&&command!=undefined){
            ws.send(JSON.stringify({ message_type: "COMMAND",data: command}));//根据后台返回的数据,需要传入一个对象,里边key值为message,并对这个对象进行序列化
            // this.ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
            command = "";
          }
  
          break;
        case "\u007F": // Backspace (DEL)
          // Do not delete the prompt
          console.log("{}:", term)
          term.write("\b \b");
          if (command.length > 0) {
            command = command.substr(
              0,
              command.length - 1
            );
          }
          break;
        default: // Print all other characters for demo
          if (
            (e >= String.fromCharCode(0x20) &&
              e <= String.fromCharCode(0x7e)) ||
            e >= "\u00a0"
          ) {
            command += e;
            writeOfColor(e, "2;3;", "33m");
            console.log("用户输入command", command);
          }
      }
    });
  }
  const close = () => {
    ws.dispose()
    addMessage(MessageType.Message, '关闭连接成功')
  }
  
  const sendMessage = () => {
    if (ws.status === 1) {
      const sendStatus = ws.send(conf.send)
      if (sendStatus) {
        addMessage(MessageType.Send, conf.send)
        console.log("发送成功")
      }
    } else {
      console.log("未连接")
    }
  }
  </script>
  